<?php


namespace Task;

use models\Business\TencentOauth;
use swoole_websocket_server;
use youliPhpLib\Common\StringOperation;

class WsServer
{
    private $server;
    private $redis;
    private $log_path;

    const REDIS_HOST = '127.0.0.1';
    const REDIS_PORT = '6379';
    const REDIS_AUTH = 'foobared';

    public function __construct() {
        date_default_timezone_set("PRC");
        $this->log_path = realpath(__DIR__) . '/log/websocket_server' . date('Y-m-d', time()) . '.log';

        $this->server = new swoole_websocket_server("0.0.0.0", 19992);
        $this->server->set([
            'worker_num' => 2, //开启2个worker进程
            'max_request' => 4, //每个worker进程 max_request设置为4次
            'task_worker_num' => 4, //开启4个task进程
            'dispatch_mode' => 4, //数据包分发策略 - IP分配
            'daemonize' => 1, //守护进程(true/false)
        ]);

        $this->server->on('Start', [$this, 'onStart']);
        $this->server->on('Open', [$this, 'onOpen']);
        $this->server->on("Message", [$this, 'onMessage']);
        $this->server->on("Close", [$this, 'onClose']);
        $this->server->on("Task", [$this, 'onTask']);
        $this->server->on("Finish", [$this, 'onFinish']);

        $this->redis = new \Redis();
        $this->redis->connect(self::REDIS_HOST, self::REDIS_PORT);
        $this->redis->auth(self::REDIS_AUTH);

        $this->server->start();
    }

    public function onStart($server) {
        self::log($this->log_path, "服务已启动");
        self::log($this->log_path, "master_pid: {$server->master_pid}");
        self::log($this->log_path, "manager_pid: {$server->manager_pid}");
    }

    public function onOpen($server, $request) {
        self::log($this->log_path, "server: handshake success with fd{$request->fd}");
        self::log($this->log_path, "master_pid: {$server->master_pid}");
        self::log($this->log_path, "manager_pid: {$server->manager_pid}");
        $server->task([
            'type' => 'login'
        ]);
    }

    public function onTask($server, $task_id, $from_id, $data) {
        self::log($this->log_path, "#{$server->worker_id} onTask: [PID={$server->worker_pid}]: task_id={$task_id}");
        self::log($this->log_path, "data: [" . json_encode($data) . "]");
        $msg = $state = '';
        switch ($data['type']) {
            case 'login':
                $msg = '我来了...';
                break;
            case 'speak':
                $msg = $data['msg'];
                $state = isset($data['state']) && !empty($data['state']) ? $data['state'] : '';
                break;
            case 'speakTo':
                $state = isset($data['state']) && !empty($data['state']) ? $data['state'] : '';
                break;
        }
        if ($state) {
            $fd = $this->redis->get($state);
            // fd不存在 或fd已断开链接
            if (false !== $fd && false === $server->push($fd, json_encode($data)))
                $this->redis->del($state);
        }
        /*foreach ($server->connections as $fd) {
            $connectionInfo = $server->connection_info($fd);
            if ($connectionInfo['websocket_status'] == 3) {
                $server->push($fd, $msg); //长度最大不得超过2M
            }
        }*/
        $server->finish($data);
    }

    public function onMessage($server, $frame) {
        echo "#### onMessage ####".PHP_EOL;
        self::log($this->log_path, "receive from fd{$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}");
        $data = json_decode($frame->data, true);
        if (! isset($data['action']))
            throw new \Exception("非法参数");

        if ($data['action'] == 'getState') {
            if (! isset($data['type']) || ! in_array($data['type'], ['weChat', 'qq']))
                throw new \Exception("非法type参数");

            $state = md5(uniqid(microtime(true), true) . $data['type']);

            $this->redis->select(9);
            $this->redis->set($state, $frame->fd);
            $server->task(['type' => 'speak', 'state' => $state, 'msg' => 'applied successfully']);
        } else if ($data['action'] == 'speakTo') {
            if (isset($data['state']) && !empty($data['state']))
                $server->task(['type' => 'speak', 'state' => $data['state'], 'msg' => $data['msg'], 'user_info' => $data['user_info']]);
        } else
            $server->task(['type' => 'speak', 'msg' => $frame->data]);
    }

    public function onFinish($server, $task_id, $data) {
        self::log($this->log_path, "Task {$task_id} 已完成 data:" . json_encode($data));
    }

    public function onClose($server, $fd) {
        self::log($this->log_path, "client {$fd} closed");
    }

    static protected function log($log_path = null, $content = '') {
        if (!is_null($log_path)) {
            error_log('[' . date('Y-m-d H:i:s', time()) . '] - '.$content . "\r\n", 3, $log_path);
        }
    }
}
